package com.lagou.edu.factory;

import com.lagou.edu.MyAnnotation.MyAutowired;
import com.lagou.edu.MyAnnotation.MyService;
import com.lagou.edu.MyAnnotation.MyTransactional;
import org.reflections.Reflections;
import org.springframework.util.StringUtils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class MyBeanFactory {

    private static Map<String, Object> objMap = new HashMap<>();

    static {
        try {
            //扫描包，通过反射技术获取反射对象
            Reflections edus = new Reflections("com.lagou.edu");
            Set<Class<?>> clazzs = edus.getTypesAnnotatedWith(MyService.class);
            //遍历对象集合
            for (Class<?> clazz:clazzs) {
                //获取实例化对象
                Object object = clazz.newInstance();
                MyService service = clazz.getAnnotation(MyService.class);

                //判断MyService注解上是否有自定义对象ID
                if(StringUtils.isEmpty(service.value())){
                    //由于getName获取的是全限定类名，所以要分割去掉前面包名部分
                    String name = clazz.getName();
                    String[] names = name.split("\\.");
                    objMap.put(names[names.length - 1], object);
                }else{
                    objMap.put(service.value(), object);
                }
            }

            //维护对象之间的依赖关系
            for(Map.Entry<String, Object> entrySet: objMap.entrySet()) {
                Object obj = entrySet.getValue();
                Class clazz = obj.getClass();
                //获取每个类的所有属性
                Field[] fields = clazz.getDeclaredFields();
                //遍历属性，确认是否有使用Autowired注解
                for (Field field : fields) {
                    //判断是否使用自定义注解的参数
                    if (field.isAnnotationPresent(MyAutowired.class)
                            && field.getAnnotation(MyAutowired.class).required()) {
                        String nameTxt = field.getType().getName();
                        String[] names = nameTxt.split("\\.");
                        String name = names[names.length - 1];
                        Method[] methods = clazz.getMethods();
                        for (int j = 0; j < methods.length; j++) {
                            Method method = methods[j];
                            if (("set" + name).equalsIgnoreCase(method.getName())) {
                                method.invoke(obj, objMap.get(name));
                            }
                        }
                    }
                }

                //判断当前类是否有MyTransactional注解
                if(clazz.isAnnotationPresent(MyTransactional.class)){
                    //获取代理工厂
                    ProxyFactory proxyFactory = (ProxyFactory) MyBeanFactory.getBean("proxyFactory");
                    Class[] interfaces = clazz.getInterfaces();
                    //判断对象是否实现接口
                    if(interfaces != null && interfaces.length > 0){
                        //使用jdk
                        obj = proxyFactory.getJdkProxy(obj);
                    }else{
                        //使用cglib
                        obj = proxyFactory.getCglibProxy(obj);
                    }
                }
                //重新赋值
                objMap.put(entrySet.getKey(),obj);
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }

    public static Object getBean(String beanId){
        return objMap.get(beanId);
    }

}
